#!/usr/bin/env python3.9
# -*- encoding: utf-8 -*-

import numpy as np
from rest_framework.decorators import action
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from rest_framework.viewsets import ViewSet

from mars.libs.aliyun import Aliyun
from mars.utils.common import generate_uuid_filename
from mars.utils.exceptions.enums import StatusCodeEnum
from mars.utils.exceptions.exceptions import APIException

from .serializers import (AliyunHumanStyleSerializer, AliyunImageUrlSerializer,
                          AliyunSignatureSerializer)

# Create your views here.


class AliyunAPIView(ViewSet):
    @action(
        methods=["post"], detail=False, url_path="detectface", url_name="detectface"
    )
    def detect_face(self, request, *args, **kwargs):
        """人脸关键点检测定位"""
        # 验证参数
        serializer = AliyunImageUrlSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        # 调用接口处理
        res = Aliyun.detect_face(serializer.validated_data["image_url"])

        # 重新组合数据
        eyeX = round(
            (max(res["Landmarks"][48:110:2]) + min(res["Landmarks"][48:110:2])) / 2
        )
        eyeY = round(
            (max(res["Landmarks"][49:111:2]) + min(res["Landmarks"][49:111:2])) / 2
        )
        face = res["FaceRectangles"]
        # 最终结果包含脸部区域及两眼的中间坐标
        result = {"Face": {"EyeCenter": {"x": eyeX, "y": eyeY}, "FaceRectangles": face}}

        # 返回处理结果
        return Response(result)

    @action(methods=["post"], detail=False, url_path="headinfo", url_name="gethead")
    def get_head_info(self, request, *args, **kwargs):
        # 验证参数
        serializer = AliyunImageUrlSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        # 调用接口处理
        res_person = Aliyun.detect_pedestrian(serializer.validated_data["image_url"])

        # 调用人体检测，获得图片人体的上边缘坐标
        if len(res_person["Elements"]) == 0:
            raise APIException(StatusCodeEnum.ALI_API_ERR, "请提供包含人像的图片")

        tmp_box = []  # 临时保存y坐标
        for person in res_person["Elements"]:
            tmp_box.append(person["Boxes"][1])  # 获取左上角的y坐标
        person_y = min(tmp_box)

        # 获取图片中所有人像的头部中心位置
        # 调用接口处理
        res_face = Aliyun.detect_face(serializer.validated_data["image_url"])

        # 重新组合数据
        eyexs = []  # 所有人像的眼睛中心x坐标
        eyeys = []  # 所有人像的眼睛中心y坐标
        for i in range(0, res_face["FaceCount"]):
            start = i * 210
            eye_x = (
                max(res_face["Landmarks"][start + 48 : start + 110 : 2])
                + min(res_face["Landmarks"][start + 48 : start + 110 : 2])
            ) / 2

            eye_y = (
                max(res_face["Landmarks"][start + 49 : start + 111 : 2])
                + min(res_face["Landmarks"][start + 49 : start + 111 : 2])
            ) / 2

            eyexs.append(eye_x)
            eyeys.append(eye_y)

        # 计算脸部矩形框
        np_face_rect= np.array(res_face["FaceRectangles"])

        face_rect = {
            "left": min(np_face_rect[::4]),
            "top": min(np_face_rect[1::4]),
            "right": max(np_face_rect[::4]+np_face_rect[2::4]),
            "bottom": max(np_face_rect[1::4]+np_face_rect[3::4]),
        }
        # 计算平均值
        result = {
            "EyeCenter": {
                "x": round(sum(eyexs) / len(eyexs)),
                "y": round(sum(eyeys) / len(eyeys)),
            },
            "HeadTop": person_y,
            "FaceRect": face_rect,
        }
        return Response(result)

    @action(
        methods=["post"], detail=False, url_path="humanstyle", url_name="humanstyle"
    )
    def generate_human_style(self, request, *args, **kwargs):
        """人体动漫化或素描化"""
        # 验证参数
        serializer = AliyunHumanStyleSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        # 调用处理函数
        if serializer.validated_data["style"] == "anime":
            res = Aliyun.generate_human_anime_style(
                image_url=serializer.validated_data["image_url"],
                algo_type=serializer.validated_data["algo"],
            )
        elif serializer.validated_data["style"] == "sketch":
            res = Aliyun.generate_human_sketch_style(
                serializer.validated_data["image_url"]
            )

        # 返回结果
        return Response(res)

    @action(
        methods=["post"],
        detail=False,
        url_path="recognizeface",
        url_name="recognizeface",
    )
    def recognize_face(self, request, *args, **kwargs):
        """人脸属性检测"""
        # 验证参数
        serializer = AliyunImageUrlSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        # 设置只检测年龄
        attribute = {"age": True, "gender": True}
        res = Aliyun.recognize_face(
            image_url=serializer.validated_data["image_url"], other_params=attribute
        )
        # 重新组织返回值，只返回年龄即可
        result = {
            "age": res["AgeList"],
            "gender": ["男" if i == 1 else "女" for i in res["GenderList"]],
        }
        return Response(result)

    @action(methods=["post"], detail=False, url_path="segmenthead", url_name="seghead")
    def segment_head(self, request, *args, **kwargs):
        """头像分割"""
        # 验证参数
        serializer = AliyunImageUrlSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        # 调用接口处理
        res = Aliyun.segment_head(serializer.validated_data["image_url"])

        # 返回处理结果
        return Response(res)

    @action(methods=["post"], detail=False, url_path="segmentbody", url_name="segbody")
    def segment_body(self, request, *args, **kwargs):
        """身体分割"""
        # 验证参数
        serializer = AliyunImageUrlSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        # 调用接口处理
        res = Aliyun.segment_body(serializer.validated_data["image_url"])

        # 返回处理结果
        return Response(res)

    @action(methods=["post"], detail=False, url_path="oss/signature", url_name="upload")
    def get_upload_signature(self, request):
        # 验证参数
        serializer = AliyunSignatureSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        # 生成唯一文件名
        uuid_filename = generate_uuid_filename(
            filename=serializer.validated_data["filename"]
        )

        # 生成直传签名
        signature = Aliyun.get_policy(uuid_filename)

        # 生成下载地址
        download_url = Aliyun.get_preurl("GET", uuid_filename)
        download_url = download_url.replace("http://", "https://")

        # 返回结果
        return Response({"Signature": signature, "downloadUrl": download_url})
